package cn.tedu.charging.cost.service;

import cn.tedu.charging.common.pojo.param.ProgressCostParam;
import cn.tedu.charging.common.pojo.po.ChargingCostRulePO;
import cn.tedu.charging.common.pojo.vo.ProgressCostVO;
import cn.tedu.charging.cost.dao.repository.CostRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;

@Service
@Slf4j
public class CostService {
    /*@Autowired
    private RedisTemplate redisTemplate;*/
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private CostRepository costRepository;
    public ProgressCostVO calculate(ProgressCostParam param) {
        //根据设备的充电度数 拿到单价 计算价格 相乘的关系 同时计算总价 封装vo;
        //业务难点,在cost 如何计算累加 先知道上次 多少钱,才能计算本次累加结果 totalCost????
        //1.查询当前时间点 当前设备 对应的尖峰平谷 具体计价方案 powerFee
        //select * from charging_cost_rule where station_id=? and start_time<? end_time>?
        //尖峰平谷的时间规则,在sql语句中使用where条件的 ><  时间连接点不平滑 14 18 0 8 12 14 18 24
        //表达式 必须保证中间小时数 存在所有范围之内 [0,8) [8,12)
        ChargingCostRulePO costRule=getCostRule(param.getStationId(), LocalDateTime.now().getHour());
        log.debug("当前订单计价规则:{}",costRule);
        //2.计算一下单次金额 powerFee*param.chapacity
        BigDecimal cost=calculateCost(param,costRule);
        //3.使用redis客户端执行incrby 做缓存数据累加存储
        BigDecimal totalCost=accumulateCost(param.getOrderNo(),cost);
        //4.封装VO返回
        ProgressCostVO vo=new ProgressCostVO();
        vo.setTotalCost(totalCost.doubleValue());
        vo.setPowerFee(costRule.getPowerFee().doubleValue());
        return vo;
    }

    private BigDecimal accumulateCost(String orderNo, BigDecimal cost) {
        //1.生成一个订单的计价总金额的key
        String orderKey="charging:order:total:"+orderNo;
        //使用redis做incrby操作 必须保证 value值序列化是string 而不是 java
        //2.不管当前订单是不是第一次计算金额,都可以执行命令后 使用返回值作为totalCost使用
        Double increment = stringRedisTemplate.opsForValue().increment(orderKey, cost.doubleValue());
        log.debug("本次累加金额:{}",increment);
        return new BigDecimal(increment);
    }

    private BigDecimal calculateCost(ProgressCostParam param, ChargingCostRulePO costRule) {
        //计算公式 本次价格 powerFee单价 * chapacity充电度数
        BigDecimal chargingCapacity = new BigDecimal(param.getChargingCapacity());
        BigDecimal powerFee = costRule.getPowerFee();
        //乘法 浮点数 需要做四舍五入 取小数点 前两位
        BigDecimal cost = powerFee.multiply(chargingCapacity).setScale(
                2,BigDecimal.ROUND_HALF_UP);
        //setScale定义 取小数点位数的逻辑 2 取两位 BigDecimal 规则
        //ROUND_HALF_UP 0.257 -> 0.26 后一位大于等于5 进一
        //ROUND_HALF_DOWN 0.257 -> 0.25 后一位小于等于4 进一
        //ROUND_HALF_EVEN 0.257 -> 0.26 后一位和奇数偶数有关
        //ROUND_CEILING 0.251 -> 0.26 后一位大于等于5 进一
        //...
        return cost;
    }

    private ChargingCostRulePO getCostRule(Integer stationId, Integer hour) {
        //cache-aside 缓存流程 因为多次 查询po对象 每次都是固定数据 使用缓存流程
        return costRepository.getCostRule(stationId,hour);
    }
}
